package dcutils.tuples;

// Import Java JDK Classes
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

/**
* Contains exactly seven items.<br/>
* @author dca
*/
public class Septet<A, B, C, D, E, F, G> implements Iterable<Object>, Comparator<Object> {
   /** The first item of the septet.<br/> */
   private A first;

   /** The second item of the septet.<br/> */
   private B second;

   /** The third item of the septet.<br/> */
   private C third;

   /** The fourth item of the septet.<br/> */
   private D fourth;

   /** The fifth item of the septet.<br/> */
   private E fifth;

   /** The sixth item of the septet.<br/> */
   private F sixth;

   /** The seventh item of the septet.<br/> */
   private G seventh;

   /**
    * The constructor initializes the items of the septet.<br/>
    * @param first The first item of the septet.<br/>
    * @param second The second item of the septet.<br/>
    * @param third The third item of the septet.<br/>
    * @param fourth The fourth item of the septet.<br/>
    * @param fifth The fifth item of the septet.<br/>
    * @param sixth The sixth item of the septet.<br/>
    * @param seventh The seventh item of the septet.<br/>
    */
   public Septet(A first, B second, C third, D fourth, E fifth, F sixth, G seventh) {
      first(first);
      second(second);
      third(third);
      fourth(fourth);
      fifth(fifth);
      sixth(sixth);
      seventh(seventh);
   } // END constructor

   /**
    * The getter for the first item.<br/>
    * Returns the first item of the septet.<br/>
    * @return first The first item of the septet.<br/>
    */
   public A first() {
      return first;
   } // END first

   /**
    * The setter for the first item.<br/>
    * Sets the first item of the septet.<br/>
    * @param first The first item of the septet.<br/>
    * @return this.<br/>
    */
   public Septet<A, B, C, D, E, F, G> first(A first) {
      this.first = first;
      return this;
   } // END first

   /**
    * The getter for the second item.<br/>
    * Returns the second item of the septet.<br/>
    * @return second The second item of the septet.<br/>
    */
   public B second() {
      return second;
   } // END second

   /**
    * The setter for the second item.<br/>
    * Sets the second item of the septet.<br/>
    * @param second The second item of the septet.<br/>
    * @return this.<br/>
    */
   public Septet<A, B, C, D, E, F, G> second(B second) {
      this.second = second;
      return this;
   } // END second

   /**
    * The getter for the third item.<br/>
    * Returns the third item of the septet.<br/>
    * @return third The third item of the septet.<br/>
    */
   public C third() {
      return third;
   } // END third

   /**
    * The setter for the third item.<br/>
    * Sets the third item of the septet.<br/>
    * @param third The third item of the septet.<br/>
    * @return this.<br/>
    */
   public Septet<A, B, C, D, E, F, G> third(C third) {
      this.third = third;
      return this;
   } // END third

   /**
    * The getter for the fourth item.<br/>
    * Returns the fourth item of the septet.<br/>
    * @return fourth The fourth item of the septet.<br/>
    */
   public D fourth() {
      return fourth;
   } // END fourth

   /**
    * The setter for the fourth item.<br/>
    * Sets the fourth item of the septet.<br/>
    * @param fourth The fourth item of the septet.<br/>
    * @return this.<br/>
    */
   public Septet<A, B, C, D, E, F, G> fourth(D fourth) {
      this.fourth = fourth;
      return this;
   } // END fourth

   /**
    * The getter for the fifth item.<br/>
    * Returns the fifth item of the septet.<br/>
    * @return fifth The fifth item of the septet.<br/>
    */
   public E fifth() {
      return fifth;
   } // END fifth

   /**
    * The setter for the fifth item.<br/>
    * Sets the fifth item of the septet.<br/>
    * @param fifth The fifth item of the septet.<br/>
    * @return this.<br/>
    */
   public Septet<A, B, C, D, E, F, G> fifth(E fifth) {
      this.fifth = fifth;
      return this;
   } // END fifth

   /**
    * The getter for the sixth item.<br/>
    * Returns the sixth item of the septet.<br/>
    * @return sixth The sixth item of the septet.<br/>
    */
   public F sixth() {
      return sixth;
   } // END sixth

   /**
    * The setter for the sixth item.<br/>
    * Sets the sixth item of the septet.<br/>
    * @param sixth The sixth item of the septet.<br/>
    * @return this.<br/>
    */
   public Septet<A, B, C, D, E, F, G> sixth(F sixth) {
      this.sixth = sixth;
      return this;
   } // END sixth

   /**
    * The getter for the seventh item.<br/>
    * Returns the seventh item of the septet.<br/>
    * @return seventh The seventh item of the septet.<br/>
    */
   public G seventh() {
      return seventh;
   } // END seventh

   /**
    * The setter for the seventh item.<br/>
    * Sets the seventh item of the septet.<br/>
    * @param seventh The seventh item of the septet.<br/>
    * @return this.<br/>
    */
   public Septet<A, B, C, D, E, F, G> seventh(G seventh) {
      this.seventh = seventh;
      return this;
   } // END seventh

   /**
    * Returns the septet information as a tuple.<br/>
    * The format of the tuple is: [first, second, third, fourth, fifth, sixth, seventh].<br/>
    * If any of the items are null, then the word &quot;null&quot; will be shown in its place.<br/>
    * @return String A tuple format of the septet.<br/>
    */
   @Override
   public String toString() {
      return Arrays.toString(toArray());
   } // END toString

   /**
    * Decides if an object is equal to this septet.<br/>
    * In order for an object to be equal to this septet:<br/>
    * the object must also be a septet, must not be null, and each of its items must equal this septet&apos;s items.<br/>
    * @param obj The item to check for value equality.<br/>
    * @return True or false<br/>
    */
   @Override
   public boolean equals(Object obj) {
      if(null == obj) {
         return false;
      } else if(obj instanceof Septet) {
         Septet<?, ?, ?, ?, ?, ?, ?> sep = (Septet<?, ?, ?, ?, ?, ?, ?>)obj;

         return (
            0 == compare(first,   sep.first()) &&
            0 == compare(second,  sep.second()) &&
            0 == compare(third,   sep.third()) &&
            0 == compare(fourth,  sep.fourth()) &&
            0 == compare(fifth,   sep.fifth()) &&
            0 == compare(sixth,   sep.sixth()) &&
            0 == compare(seventh, sep.seventh())
         );
      } else {
         return false;
      } // END if/else
   } // END equals

   /**
    * Compares two arguments.<br/>
    * If they are the same, &quot;0&quot; will be returned.<br/>
    * If they are different, &quot;-1&quot; will be returned.<br/>
    * This method is used primarily by the equals(Object) method to compare internal fields to those of another Septet.<br/>
    * @param lhs The left-hand-side argument.<br/>
    * @param rhs The right-hand-side argument.<br/>
    * @see #equals(Object)
    */
   @Override
   public int compare(Object lhs, Object rhs) {
      if(null == lhs ^ null == rhs) return -1; // If one or the other are null -> they are not the same.
      else if(null == lhs && null == rhs) return 0; // If both are null -> they are the same.
      else return (lhs.equals(rhs) ? 0 : -1); // If both are defined and equal -> they are the same.
   } // END compare

   /**
    * Creates a hash code for this septet.<br/>
    * The hash code uses prime numbers and the hash codes of this septet&apos;s items.<br/>
    * @return integer The hash code.<br/>
    */
   @Override
   public int hashCode() {
      int hashCode = 101;
      for(Object item : this) {
         hashCode = (11 * hashCode) + (null == item ? -1 : item.hashCode());
      } // END loop
      return hashCode;
   } // END hashCode

   /**
    * Returns an iterator over the items in this septet.<br/>
    * @return The iterator.<br/>
    */
   @Override
   public Iterator<Object> iterator() {
      final List<Object> ITEMS = new ArrayList<Object>();
      Collections.addAll(ITEMS, toArray());
      return ITEMS.iterator();
   } // END iterator

   /**
    * Creates a new array and defines it with the septet&apos;s items.<br/>
    * @return Object[] The object array of the septet&apos;s items.<br/>
    */
   public Object[] toArray() {
      return new Object[] {first, second, third, fourth, fifth, sixth, seventh};
   } // END toArray
} // END class Septet
